package com.zyt.wiki.service;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.zyt.wiki.domain.Ebook;
import com.zyt.wiki.domain.EbookExample;
import com.zyt.wiki.exception.BusinessException;
import com.zyt.wiki.exception.BusinessExceptionCode;
import com.zyt.wiki.mapper.EbookMapper;
import com.zyt.wiki.req.EbookQueryReq;
import com.zyt.wiki.req.EbookSaveReq;
import com.zyt.wiki.resp.EbookQueryResp;
import com.zyt.wiki.resp.PageResp;
import com.zyt.wiki.util.CopyUtil;
import com.zyt.wiki.util.FileUtil;
import com.zyt.wiki.util.SnowFlake;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.io.File;
import java.util.List;

@Service
public class EbookService {

    public static final Logger LOG = LoggerFactory.getLogger(EbookService.class) ;

    @Autowired  // 【Spring自带】，通过 byType 的方式去注入的， 使用该注解，要求接口只能有一个实现类
    private EbookMapper ebookMapper ;

    @Resource   // 【JDK自带】，通过 byName 和 byType的方式注入， 默认先按 byName的方式进行匹配，如果匹配不到，再按 byType的方式进行匹配
    private SnowFlake snowFlake ;

    @Value("${file.upload.path.temp}")
    private String tempFilePath ;   // 临时文件目录

    @Value("${file.upload.path.work}")
    private String workFilePath ;   // 最终文件目录

    /** 查询电子书列表，分页 */
    public PageResp<EbookQueryResp> list(EbookQueryReq req){
        EbookExample ebookExample = new EbookExample() ;
        EbookExample.Criteria criteria = ebookExample.createCriteria() ;
        // 若上送了name，则据此进行模糊查询，否则直接查询所有
        if(!ObjectUtils.isEmpty(req.getName())){
            criteria.andNameLike("%" + req.getName() + "%") ;
        }
        LOG.info("++++++++++++++++++++ pageNum: {}", req.getPageNum());
        LOG.info("++++++++++++++++++++ pageSize: {}", req.getPageSize());
        // 注意：1、仅对后面的第一个数据库操作有效 2、pageNum，从1开始 3、若pageSize为0，则不分页；若pageNum为0，则效果同第1页
        PageHelper.startPage(req.getPageNum(), req.getPageSize()) ;
        List<Ebook> ebookList = this.ebookMapper.selectByExample(ebookExample);

        PageInfo pageInfo = new PageInfo(ebookList) ;
        LOG.info("总行数: {}", pageInfo.getTotal());
        LOG.info("总页数: {}", pageInfo.getPages());

        // 列表复制
        List<EbookQueryResp> respList = CopyUtil.copyList(ebookList, EbookQueryResp.class) ;

        PageResp<EbookQueryResp> pageResp = new PageResp<>() ;
        pageResp.setTotal(pageInfo.getTotal());
        pageResp.setList(respList);
        return pageResp ;
    }

    /** 查询电子书列表，不分页 */
    public List<EbookQueryResp> all(EbookQueryReq req){
        EbookExample ebookExample = new EbookExample() ;
        EbookExample.Criteria criteria = ebookExample.createCriteria() ;
        // 若上送了category2Id，则据此进行查询，否则直接查询所有
        if(!ObjectUtils.isEmpty(req.getCategory2Id())){
            criteria.andCategory2IdEqualTo(req.getCategory2Id()) ;
        }
        List<Ebook> ebookList = this.ebookMapper.selectByExample(ebookExample);
        List<EbookQueryResp> respList = CopyUtil.copyList(ebookList, EbookQueryResp.class);
        return respList ;
    }

    /** 保存 */
    public void save(EbookSaveReq req){
        Ebook ebook = CopyUtil.copy(req, Ebook.class) ;  // Mapper操作的是Ebook对象，所以要转换一下
        String tempFile = this.tempFilePath + File.separator + ebook.getCover() ;   // 封面图片全路径名
        if(ObjectUtils.isEmpty(ebook.getId())){
            // 新增DB记录前，将封面图片从temp目录移动到work （先操作文件，再操作DB，避免插入脏数据）
            if(!FileUtil.moveFileToDir(tempFile, this.workFilePath)){
                throw new BusinessException(BusinessExceptionCode.MOVE_FILE_ERROR) ;
            }
            // 新增 （前端没有上送主键Id）
            ebook.setId(this.snowFlake.nextId());
            // 新增时，文档数/阅读数/点赞数前端均未上送，此处获取为null，使用...Selective方法，没有值的字段不更新，避免触发DB的必须字段校验报错
            this.ebookMapper.insertSelective(ebook) ;
        }else {
            // 若修改了封面（上送cover且与DB中的cover不一样），则也要将封面图片从temp目录移动到work
            Ebook ebookDb = this.ebookMapper.selectByPrimaryKey(ebook.getId());
            String oldCover = ebookDb.getCover() ;
            if(!ObjectUtils.isEmpty(ebook.getCover()) && !ebook.getCover().equals(oldCover)){
                LOG.info("修改时，涉及封面图片从temp目录移动到work") ;
                // 新封面图片，从temp目录移动到work
                if(!FileUtil.moveFileToDir(tempFile, this.workFilePath)){
                    throw new BusinessException(BusinessExceptionCode.MOVE_FILE_ERROR) ;
                }
                // 旧图片删除
                String oldFile = this.workFilePath + File.separator + oldCover ;
                if(!FileUtils.deleteQuietly(new File(oldFile)) ){
                    LOG.info("更新电子书时，原封面图片删除失败, {}", oldFile) ;
                }
            }
            // 修改DB
            this.ebookMapper.updateByPrimaryKey(ebook) ;
        }
    }

    /** 删除 */
    public void delete(Long id){
        Ebook ebookDb = this.ebookMapper.selectByPrimaryKey(id);
        String oldCover = ebookDb.getCover() ;
        // 删除DB
        this.ebookMapper.deleteByPrimaryKey(id) ;
        //删除图片 （不要影响交易结果）
        String oldFile = this.workFilePath + File.separator + oldCover ;
        if(!FileUtils.deleteQuietly(new File(oldFile)) ){
            LOG.info("删除电子书时，原封面图片删除失败, {}", oldFile) ;
        }
    }

}
